Skip to content

✨ DDSP trainable filters, .compile()/.freeze(), CLI pipeline + .fxg, realtime param ramping - #103

Merged
matteospanio merged 3 commits into
devfrom
feat/ddsp-compile-cli
Jun 26, 2026
Merged

matteospanio merged 3 commits into
devfrom
feat/ddsp-compile-cli

Conversation

@matteospanio

Copy link
Copy Markdown
Owner

Summary

Back-ports six design ideas from the Fluxion proposal (PROJECT.md) into the PyTorch codebase. Deterministic filters are unchanged (still @torch.no_grad()), so non-DDSP users pay zero overhead.

What's included

1. torchfx.ddsp — opt-in differentiable filters

  • LearnableFilter abstract base (extension point: implement sos()), mirroring filter.AbstractFilter's compute_coefficients().
  • Ready-made subclasses: LearnableLowpass, LearnableHighpass, LearnablePeaking, LearnableParametricEQ.
  • BiquadFunction — a torch.autograd.Function with a hand-derived analytic backward that reuses the native forward kernel (the adjoint of an LTI filter is itself a filter), avoiding the ~30× cost of unrolling the IIR recursion under autograd. differentiable_sos_cascade composes a cascade.
  • LearnableGain — shows trainable effects (pointwise → plain autograd). Recursive/native-kernel effects (Delay/Reverb/dynamics) would each need their own analytic-backward Function; documented, not auto-covered.
  • freeze() bridges any learnable module to a deterministic filter.SOSFilter for fast inference.

2. Explicit .compile() / .freeze()

Lazy coefficient design stays the default; FX.compile(fs) / FilterChain.compile(fs) eagerly design coefficients (no first-forward mutation), freeze() locks them. Works on a lone filter or a chain. FilterChain.summary() renders the topology + fused SOS plan.

3. CLI

  • torchfx pipe IN OUT lowpass --cutoff 800 reverb --mix 0.4 (SoX-style positional pipeline)
  • torchfx compile "<pipeline>" --fs 48000 -o chain.fxg → portable .fxg artifact (filters as precomputed SOS, other effects as specs)
  • torchfx process --compiled chain.fxg

4. Realtime smoothed parameter automation

set_parameter(name, value, ramp_ms=...) ramps a parameter at block granularity instead of jumping (no zipper noise); filter coefficients recompute each block without resetting DF1 state, so sweeps stay continuous.

Internal

Shared apply_fs (_config.py) and build_fused_plan extracted from Wave; new filter.SOSFilter (raw-SOS deterministic node).

Testing

  • New: tests/test_ddsp.py (gradcheck of the VJP, scipy forward parity, train + freeze, custom subclass, learnable gain), tests/test_cli_pipeline.py (parser + .fxg roundtrip + CLI), realtime ramp tests in tests/test_realtime.py.
  • Full suite: 1442 passed, 73 skipped (CUDA). ruff + black + mypy --strict clean.

Known limitation

.compile()/.freeze() remove the lazy first-forward mutation (so torch.compile works, graph-breaking around the native kernel), but full torch.export of the forward additionally needs the native SOS kernel registered as a custom op — left as a follow-up. CUDA tests not run locally (no GPU here); the differentiable path only calls the already-CUDA-tested biquad_forward.

🤖 Generated with Claude Code

matteospanio and others added 2 commits June 26, 2026 11:55
…e + .fxg, realtime param ramping

Back-ports six design ideas from the Fluxion proposal (PROJECT.md) into the
PyTorch codebase. Deterministic filters are unchanged (still @torch.no_grad()),
so non-DDSP users pay no overhead.

- ddsp (new, opt-in): LearnableFilter abstract base (extension point: sos())
  with LearnableLowpass/Highpass/Peaking/ParametricEQ; BiquadFunction analytic
  VJP (reuses the native forward kernel; no autograd unrolling) +
  differentiable_sos_cascade; LearnableGain shows trainable effects. freeze()
  bridges any of these to a deterministic filter.SOSFilter for fast inference.
- filters/chains: FX.compile(fs)/freeze() eagerly design coefficients (lazy
  stays the default); _frozen forward guard; FilterChain.summary(); shared
  apply_fs (src/torchfx/_config.py) and build_fused_plan extracted from Wave.
- cli: `torchfx pipe` SoX-style positional pipeline, `torchfx compile` -> .fxg
  artifact, `torchfx process --compiled`; new parse_pipeline reuses the registry.
- realtime: set_parameter(name, value, ramp_ms=...) block-rate smoothing;
  filter coeffs recomputed per block without resetting DF1 state (clickless sweep).
- tests: gradcheck + scipy parity + train/freeze (test_ddsp.py), CLI pipeline +
  .fxg roundtrip (test_cli_pipeline.py), ramp tests (test_realtime.py).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@matteospanio
matteospanio requested a review from Copilot June 26, 2026 10:19
@matteospanio matteospanio self-assigned this Jun 26, 2026
@matteospanio matteospanio added enhancement New feature or request cli Command-line interface labels Jun 26, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds an opt-in differentiable DSP (DDSP) stack for trainable IIR filters, introduces explicit coefficient “eagerization” via .compile(fs) / .freeze(), and extends the CLI with a SoX-style pipeline plus a portable compiled .fxg artifact, alongside realtime smoothed parameter ramping.

Changes:

  • Introduce torchfx.ddsp (learnable filters/effects, differentiable SOS cascade w/ analytic VJP, DDSP losses) plus deterministic filter.SOSFilter for “train → freeze → fast inference”.
  • Add explicit .compile(fs) / .freeze() on FX and FilterChain, plus shared fs-injection helpers and shared fused-plan building.
  • Add CLI positional pipeline parsing (torchfx pipe) and compiled pipeline artifacts (torchfx compile / torchfx process --compiled), and realtime block-rate ramping for parameters.

Reviewed changes

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_realtime.py Adds tests for gradual parameter ramping and filter cutoff ramping.
tests/test_ddsp.py Adds DDSP gradcheck, parity, training, and freeze-bridge tests.
tests/test_cli_pipeline.py Adds tests for pipeline parsing, .fxg roundtrip, and CLI commands.
src/torchfx/wave.py Refactors plan building and fs-application to shared helpers.
src/torchfx/realtime/processor.py Adds ramp_ms parameter automation with worker-thread ramp stepping.
src/torchfx/filter/sos.py Introduces deterministic SOSFilter wrapper over precomputed SOS.
src/torchfx/filter/iir.py Adds frozen-mode guard to skip fs/fingerprint recompute checks.
src/torchfx/filter/fused.py Extracts shared build_fused_plan for SOS fusion lowering.
src/torchfx/filter/biquad.py Adds frozen-mode guard to skip fs/fingerprint recompute checks.
src/torchfx/filter/init.py Exports SOSFilter.
src/torchfx/filter/__base.py Adds _frozen flag to AbstractFilter for freeze semantics.
src/torchfx/effect.py Adds FX.compile(fs) and FX.freeze(fs=None) APIs.
src/torchfx/ddsp/losses.py Adds DDSP multi-resolution STFT reconstruction loss.
src/torchfx/ddsp/filter.py Adds LearnableFilter base + learnable filter implementations and freeze() bridge.
src/torchfx/ddsp/effect.py Adds LearnableGain (trainable pointwise effect) + discussion of limitations.
src/torchfx/ddsp/coeffs.py Adds differentiable RBJ SOS coefficient helpers + SOS frequency response.
src/torchfx/ddsp/_autograd.py Adds differentiable SOS cascade and BiquadFunction analytic backward.
src/torchfx/ddsp/init.py Exposes DDSP public API surface.
src/torchfx/chain.py Adds FilterChain.compile/fs, freeze, and summary() including fused-plan.
src/torchfx/_config.py Adds shared apply_fs / freeze_fx helpers for eager coefficient design.
src/torchfx/init.py Exposes torchfx.ddsp from package root.
src/cli/parsing.py Adds SoX-style positional pipeline parsing on top of the effect registry.
src/cli/commands/process.py Adds --compiled support to apply a precompiled .fxg pipeline.
src/cli/commands/pipeline.py Adds torchfx pipe command to process files with positional pipelines.
src/cli/commands/compile.py Adds torchfx compile and .fxg save/load helpers.
src/cli/app.py Registers new pipe and compile CLI commands.
examples/ddsp_graphic_eq.py Updates example to use torchfx.ddsp time-domain differentiable cascade.
CHANGELOG Documents new DDSP, compile/freeze, CLI pipeline + .fxg, and realtime ramps.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/torchfx/ddsp/_autograd.py
Comment thread src/torchfx/ddsp/_autograd.py
Comment thread src/torchfx/ddsp/losses.py
Address Copilot review on #103:
- BiquadFunction.forward/backward flatten any leading dims to [N, T] for
  the native kernel (which TORCH_CHECKs x.dim()==2) and restore the shape,
  matching the convention used by every other torchfx._ops dispatcher. The
  docstring already advertised [B, C, T]; it now actually works.
- multires_stft_loss builds the Hann window with dtype=x.dtype to avoid a
  latent float32->float64 promotion inside torch.stft.
- Add a [B, C, T] regression test (per-channel parity + grad flow).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@matteospanio
matteospanio merged commit 4f0dfff into dev Jun 26, 2026
24 checks passed
@matteospanio
matteospanio deleted the feat/ddsp-compile-cli branch June 26, 2026 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli Command-line interface enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants